package com.jing21.learn.authorizationservice.configuration;

import com.jing21.learn.authorizationservice.services.CustomRedirectStrategy;
import com.jing21.learn.authorizationservice.services.CustomUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;

/**
 * Created by 郑靖 on 2017/9/16.
 */
@Configuration
@EnableResourceServer
@EnableAuthorizationServer
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    CustomUserDetailService userDetailsService;

    @Autowired
    DataSource dataSource;

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Bean
    protected AuthorizationCodeServices authorizationCodeServices() {
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    @Bean
    public TokenStore tokenStore() {

        return new JdbcTokenStore(dataSource);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
//                .passwordEncoder(passwordEncoder)
                .tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore()).userDetailsService(userDetailsService)
                .authorizationCodeServices(authorizationCodeServices())
                .authenticationManager(authenticationManager).approvalStoreDisabled()
                //RefreshTokens 使用一次就重置
                .reuseRefreshTokens(false);
    }

    @Order(-22)
    @Configuration
    protected static class ResourceServer extends WebSecurityConfigurerAdapter {


        @Value("${server.context-parameters.gateway-path:}")
        private String gatewayPath;

        @Bean
        public SavedRequestAwareAuthenticationSuccessHandler savedRequestAwareAuthenticationSuccessHandler() {

            SavedRequestAwareAuthenticationSuccessHandler auth = new SavedRequestAwareAuthenticationSuccessHandler();
            CustomRedirectStrategy redirectStrategy = new CustomRedirectStrategy();
            redirectStrategy.setUrl(gatewayPath);
            redirectStrategy.setContextRelative(true);
            auth.setRedirectStrategy(redirectStrategy);
            auth.setDefaultTargetUrl(gatewayPath);

            return auth;
        }

        @Autowired
        private AuthenticationManager authenticationManager;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            /*
             * http.formLogin().loginPage("/login").permitAll().and().
			 * authorizeRequests() .anyRequest().authenticated();
			 */

            http.formLogin().loginPage("/login").successForwardUrl(gatewayPath).permitAll()
                    .successHandler(savedRequestAwareAuthenticationSuccessHandler()).failureForwardUrl(gatewayPath)
                    .and()
                    .logout().logoutSuccessUrl(gatewayPath).permitAll().and()
                    .requestMatchers()
                    .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access").and().authorizeRequests()
                    .anyRequest().authenticated();
            if (!StringUtils.isEmpty(gatewayPath)) {
                http.formLogin().loginPage(gatewayPath + "login");
            }
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.parentAuthenticationManager(authenticationManager);
        }


    }
}
